<template>
<div class="right-area" ref="right">
  <div v-if="nodes.length" v-for="node in nodes" class="node" :class="node.className" :key="node.id" :id="node.id" ref="nodes" :style="node.style" @dblclick="editNodeText(node)">
    <br>{{ node.text }}</div>
  <!-- <el-button class="demo" type="primary" @click="getAllNodes">获取所有节点</el-button> -->
  <!-- <el-button class="demo" type="primary" @click="getAlledges">获取所有连接</el-button> -->
  <div class="demo">
    <Button type="primary" @click="commitDatas" style="margin:5px">保存</Button>
    <Button type="primary" @click="clearAll" style="margin:5px">清除</Button>
    <Button type="primary" @click="reload" style="margin:5px">重现</Button>
    <div style="width:300pxl;float:right;border:1px solid #333;">
      <Form ref="flow" :model="flowItem" :label-width="40">
        <div class="formLogin-title" style="text-align:center; border-bottom: 1px solid #333;">
          <h3>流程属性</h3>
        </div>
        <Form-item label="名称" prop="Name">
          <Input type="text" v-model="flowItem.Name" placeholder="流程名称">
          </Input>
        </Form-item>
        <Form-item label="业务表名称" prop="Busyname">
        <Input v-model="flowItem.Busyname" placeholder="请输入" ></Input>
      </Form-item>
        <Form-item label="说明" prop="Remark">
          <Input type="textarea" v-model="flowItem.Remark" placeholder="流程说明">
          </Input>
        </Form-item>
      </Form>
    </div>
  </div>
  <Modal title="流程信息" v-model="flowVisible" :mask-closable="false" class="editm" @on-ok="asyncOK" @on-cancel="asynCancel">
    <Form ref="flowForm" :model="flowItem" :label-width="80" :rules="ruleFlow">
      <Form-item label="流程标识" prop="Id">
        <Input v-model="flowItem.Id" placeholder="流程标识" disabled @on-enter="asyncOK()"></Input>
      </Form-item>
      <Form-item label="流程名称" prop="Name">
        <Input v-model="flowItem.Name" placeholder="请输入" @on-enter="asyncOK()"></Input>
      </Form-item>
      <Form-item label="业务表名称" prop="Busyname" required>
        <Input v-model="flowItem.Busyname" placeholder="请输入" @on-enter="asyncOK()"></Input>
      </Form-item>
      <Form-item label="说明" prop="Remark">
        <Input v-model="flowItem.Remark" type="textarea" :autosize="{minRows: 2,maxRows: 5}" placeholder="请输入...">
        </Input>
      </Form-item>
    </Form>
  </Modal>
  <Modal :title="`请${dialogTitle}`" v-model="connectVisible">
    <Form ref="connectForm" :model="formConnect" :label-width="80" >
      <Form-item label="触发事件" prop="Event" required>
        <Select v-model="formConnect.Event" placeholder="请选择">
            <Option v-for="item  in eventList" :value="item.Id" :key="item.Id">{{item.Name}}</Option>
          </Select>
      </Form-item>
      <Form-item label="动作" prop="Action" required>
        <Select v-model="formConnect.Action" placeholder="请选择">
            <Option v-for="item  in actionList" :value="item.Id" :key="item.Id">{{item.Name}}</Option>
          </Select>
      </Form-item>
    </Form>
    <div slot="footer" class="dialog-footer">
      <Button type="error" @click="remove" v-show="dialogTitle.startsWith('编辑')">
          删除{{dialogTitle.substr(2,2)}}
        </Button>
      <Button @click="closeDialog">取 消</Button>
      <Button type="primary" @click="summit">确 定</Button>
    </div>
  </Modal>
  <Modal :title="`请${dialogTitle}`" v-model="stateVisible">
    <Form ref="stateForm" :model="formState" :label-width="80" :rules="ruleState">
      <Form-item label="节点名称" prop="Name" required>
        <Input v-model="formState.Name" placeholder="请输入" @on-enter="asyncOK()"></Input>
      </Form-item>
      <Form-item v-if="dialogType==='task'" label="角色" prop="Role" required>
        <Select v-model="formState.Role" placeholder="请选择">
            <Option v-for="item  in roleList" :value="item.Id" :key="item.Id">{{item.Name}}</Option>
          </Select>
      </Form-item>
      <Form-item label="说明" prop="Remark">
        <Input v-model="formState.Remark" type="textarea" :autosize="{minRows: 2,maxRows: 5}" placeholder="请输入...">
        </Input>
      </Form-item>
    </Form>
    <div slot="footer" class="dialog-footer">
      <Button type="error" @click="remove" v-show="dialogTitle.startsWith('编辑')">
          删除{{dialogTitle.substr(2,2)}}
        </Button>
      <Button @click="closeDialog">取 消</Button>
      <Button type="primary" @click="summit">确 定</Button>
    </div>
  </Modal>
</div>
</template>

<script>
import api from '../../api'
import {
  mapMutations,
  mapGetters,
  mapState
} from 'vuex'
const DynamicAnchors = ['Left', 'Right', 'Top', 'Bottom']
const sourceAnchors = ["RightMiddle", "BottomCenter"]
const targetAnchors = ["LeftMiddle", "TopCenter"]

const connectorStyle = {
  stroke: '#7AB02C',
  strokeWidth: 2,
  joinstyle: 'round'
}

const connectorHoverStyle = {
  stroke: '#5c96bc',
  strokeWidth: 3
}

const endpointStyle = {
  fill: 'transparent',
  stroke: '#7AB02C',
  radius: 7,
  strokeWidth: 1
}

const endpointHoverStyle = {
  fill: '#5c96bc',
  stroke: '#5c96bc',
  radius: 7,
  strokeWidth: 1
}

const anEndpoint = {
  connector: "Flowchart",
  endpoint: 'Dot',
  isSource: true,
  isTarget: true,
  paintStyle: endpointStyle,
  hoverPaintStyle: endpointHoverStyle,
  connectorStyle: connectorStyle,
  connectorHoverStyle: connectorHoverStyle,
  maxConnections: 10
}
const sourceEndpoint = {
  connector: "Flowchart",
  endpoint: 'Dot',
  isSource: true,
  // isTarget: true,
  paintStyle: endpointStyle,
  hoverPaintStyle: endpointHoverStyle,
  connectorStyle: connectorStyle,
  connectorHoverStyle: connectorHoverStyle,
  dragOptions: {},
  maxConnections: -1
}
const targetEndpoint = {
  connector: "Flowchart",
  endpoint: 'Dot',
  // isSource: true,
  isTarget: true,
  // paintStyle: endpointStyle,
  hoverPaintStyle: endpointHoverStyle,
  dropOptions: {
    hoverClass: "hover",
    activeClass: "active"
  },
  // connectorStyle: connectorStyle,
  // connectorHoverStyle: connectorHoverStyle,
  maxConnections: -1
}
const Common = {
  // anchor: DynamicAnchors,
  connector: 'State Machine ',
  endpoint: 'Dot',
  paintStyle: connectorStyle,
  hoverPaintStyle: connectorHoverStyle,
  endpointStyle,
  endpointHoverStyle,
  // maxConnections: 1,
}

export default {
  name: 'RightArea',
  props: {
    jsp: {
      type: Object
    },
    flowdata: {
      type: Object
    },
    pos: {
      type: Array
    }
  },
  data() {
    return {
      datas: null,
      connectVisible: false,
      stateVisible: false,
      flowVisible: false,
      dialogTitle: '',
      dialogText: '',
      dialogType: '', //编辑属性
      nodes: [],
      roleList: [],
      actionList: [],
      eventList: [],
      //flow数据编辑表单
      flowItem: {
        Name: '',
        Busyname:'',
        Id: '',
        Organization: '',
        OrgName: '',
        Remark: ''
      },
      //flow数据编辑表单校验
      ruleFlow: {
        Name: [{
          required: true,
          message: '名称不能为空',
          trigger: 'blur'
        }],
        Busyname: [{
          required: true,
          message: '业务名称不能为空',
          trigger: 'blur'
        }]
      },
      //State数据编辑表单
      formState: {
        Name: '',
        Id: '',
        Flow: '',
        Role: '',
        Type: '',
        Organization: '',
        OrgName: '',
        Remark: ''
      },
      //State数据编辑表单校验
      ruleState: {
        Name: [{
          required: true,
          message: '名称不能为空',
          trigger: 'blur'
        }]
      },
      //Connect数据编辑表单
      formConnect: {
        Event: '',
        Action: '',
        Id: '',
        Flow: '',
        Role: '',
        Type: '',
        Organization: '',
        OrgName: '',
        Remark: ''
      },
      info: null, //连接信息
      rjsp: this.$jsplumb.getInstance({
        ConnectionOverlays: [
          ['Arrow', {
            location: 1,
            id: 'arrow',
            width: 11,
            length: 11
          }],
          ['Label', {
            location: 0.3,
            id: 'label',
            cssClass: 'jsp-label',
            events: {
              dblclick: this.editLabelText
            }
          }]
        ]
      })
    }
  },
  computed: {
    ...mapState(['isLogin', 'captchaUrl', 'cptId', 'msg']),
  },
  methods: {
    init() {
      this.jsp.droppable(this.$refs.right, {
        drop: this._jspDrop
      })
      this.rjsp.bind('beforeDrop', this._jspBeforeDrop)
      this._fetchData()
      setTimeout(() => {
        this.saveDatas()
      }, 1000)

    },
    getRole() {
      this.spinShow = true
      this.$api.getRoleList().then(res => {
        if (!res.error) {
          this.roleList =res.Data
        } else {
          this.$Message.error(res.message)
        }
      })
    },
    getAction() {
      this.spinShow = true
      this.$api.getAction().then(res => {
        if (!res.error) {
          this.actionList =res.Data
        } else {
          this.$Message.error(res.message)
        }
      })
    },
    getEvent() {
      this.spinShow = true
      this.$api.getEvent().then(res => {
        if (!res.error) {
          this.eventList =res.Data
        } else {
          this.$Message.error(res.message)
        }
      })
    },
    _jspDrop(info) {
      // if (this.flowItem.Id) {
      this.info = info
      this.dialogType = info.drag.el.getAttribute("typeid")
      this.openDialog('输入新建节点的文本')
      // }
    },
    _jspBeforeDrop(info) {
      info.targetId = info.dropEndpoint.elementId
      info.uuids = [info.connection.endpoints[0].getUuid(), info.dropEndpoint.getUuid()]
      let connections = this.rjsp.getConnections({
        source: info.sourceId,
        target: info.targetId
      })
      if (connections.length === 0) { // 检察是否已经建立过连接
        this.info = info
        this.openDialog('输入新建连接的文本')
      } else {
        this.editLabelText(connections[0].getOverlay('label'))
      }
    },
    openDialog(title) {
      this.dialogTitle = title
      if (this.dialogTitle === '输入新建节点的文本') {
        this.stateVisible = true
      } else if (this.dialogTitle === '编辑节点的文本') {
        this.stateVisible = true
      } else if (this.dialogTitle === '输入新建连接的文本') {
        this.connectVisible = true
      } else if (this.dialogTitle === '编辑连接的文本') {
        this.connectVisible = true
      }
      // this.closeDialog()
    },
    closeDialog() {
      this.$refs.connectForm.resetFields()
      this.$refs.stateForm.resetFields()
      this.connectVisible = false
      this.stateVisible = false
    },
    editNodeText(info) {
      this.dialogText = info.text
      this.dialogType = info.className
      this.formState.Name = info.text
      this.formState.Id = info.id
      this.formState.Role = info.role
      this.info = info
      this.openDialog('编辑节点的文本')
    },
    editLabelText(info) {
      this.dialogText = info.labelText
      this.info = info.component
      console.log(info)
      this.formConnect.Action=info.component.scope
      this.formConnect.Event=this.getEventId(info.labelText)
      this.openDialog('编辑连接的文本')
    },
    summit() {
      if (this.dialogTitle === '输入新建节点的文本') {
        this.nodes.push(this._createNode(this.info.drag.el, this.info.drop.el))
        this.$nextTick(_ => this._initNode(this.$refs.nodes[this.nodes.length - 1]))
      } else if (this.dialogTitle === '编辑节点的文本') {
        this.info.text = this.formState.Name
        this.info.role = this.formState.Role
      } else if (this.dialogTitle === '输入新建连接的文本') {
        this._addEdge(this.info)
      } else if (this.dialogTitle === '编辑连接的文本') {
        let labelText = this.getEventName(this.formConnect.Event)
        this.info.scope = this.formConnect.Action
        this.$nextTick(_ => (this.info.getOverlay('label').setLabel(labelText)))
      }
      this.closeDialog()
    },
    saveDatas() {
      this.datas = {
        nodes: this.nodes.map((node, index) => {
          node.style = this._getStyle(this.$refs.nodes[index])
          return node
        }),
        edges: this.rjsp.getAllConnections().map(connection => {
          return {
            source: connection.sourceId,
            target: connection.targetId,
            uuids: [connection.endpoints[0].getUuid(), connection.endpoints[1].getUuid()],
            event: this.getEventId(connection.getOverlay('label').labelText),
            action: connection.scope,
            labelText: connection.getOverlay('label').labelText
          }
        }),
        flow: this.flowItem
      }
    },
    commitDatas() {
      this.saveDatas()
      console.log(this.datas)
      if (this.flowdata.edit) {
        this.$api.UpdateFlow(this.datas).then(res => {
          if (!res.error) {
            this.$Message.success(res.message)
            this.$router.push({
              name: '流程管理'
            })
          } else {
            this.$Message.error(res.message, 4)
          }
        }, err => {
          this.$Message.error(res.message, 4)
        })
      }else{
        this.$api.AddFlow(this.datas).then(res => {
          if (!res.error) {
            this.$Message.success(res.message)
            this.$router.push({
              name: '流程管理'
            })
          } else {
            this.$Message.error(res.message, 4)
          }
        }, err => {
          this.$Message.error(res.message, 4)
        })
      }
    },
    _getStyle(node) {
      let container = this.$refs.right.getBoundingClientRect()
      let rect = node.getBoundingClientRect()
      return {
        left: rect.left - container.left - node.clientLeft + 'px',
        top: rect.top - container.top - node.clientTop + 'px',
        // lineHeight: node.clientHeight + 'px'
      }
    },
    newData() {
      this.clearAll()
      // this.flowItem = {}
      // this.flowItem.Status = 1
      this.$refs.flowForm.resetFields()
      this.flowItem.Id = this.$util.uuid()
      this.flowVisible = true
      this.jsp.droppable(this.$refs.right, {
        drop: this._jspDrop
      })
      this.rjsp.bind('beforeDrop', this._jspBeforeDrop)
    },
    asyncOK() {
      this.$refs['flowForm'].validate((valid) => {
        if (valid) {
          this.flowVisible = false
        }else{
           this.$Message.error('表单验证失败!')
           setTimeout(() => {
              this.flowVisible = true
            }, 500)          
        }
      })      
    },
    asynCancel(){
      this.flowVisible = false
      this.$router.push({
              name: '流程管理'
            })
    },
    clearAll() {
      this.rjsp.reset()
      this.nodes = []
    },
    reload() {
      this.clearAll()
      this.rjsp.bind('beforeDrop', this._jspBeforeDrop)
      this.nodes = this.datas.nodes
      this.$nextTick(_ => {
        this._initNodes(this.$refs.nodes)
        this._initEdges(this.datas.edges)
      })
    },
    remove() {
      if (this.dialogTitle === '编辑节点的文本') {
        this._removeNode(this.info)
      } else if (this.dialogTitle === '编辑连接的文本') {
        this._removeEgde(this.info)
      }
      this.closeDialog()
    },
    _removeNode(node) {
      this.rjsp.deleteConnectionsForElement(node.id)
      this.saveDatas()
      this.datas.nodes.splice(this.datas.nodes.findIndex(n => n.id === node.id), 1)
      this.reload()
    },
    _removeEgde(egde) {
      this.rjsp.deleteConnection(egde)
      this.saveDatas()
    },
    _addEdge(info) {
      let labelText = this.getEventName(this.formConnect.Event)
      let c = this.rjsp.connect({
        uuids: info.uuids,
        // source: info.sourceId,
        // target: info.targetId,
        // scope: this.formConnect.Action,
        editable: true
      }, Common)
      c.scope = this.formConnect.Action
      this.$nextTick(_ => c.getOverlay('label').setLabel(labelText))
    },
    getEventName(id) {
      let n = ''
      for (let e in this.eventList) {
        if (this.eventList[e].Id === id) {
          n = this.eventList[e].Name
        }
      }
      return n
    },
    getEventId(name) {
      let n = ''
      for (let e in this.eventList) {
        if (this.eventList[e].Name === name) {
          n = this.eventList[e].Id
        }
      }
      return n
    },
    _createNode(dragEl, dropEl) {
      let rect = dropEl.getBoundingClientRect()
      return {
        className: dragEl.getAttribute("typeid"),
        id: this.$util.uuid(),
        text: this.formState.Name,
        role: this.formState.Role,
        style: {
          left: this.pos[0] - rect.left - dragEl.clientLeft + 'px',
          top: this.pos[1] - rect.top - dragEl.clientTop + 'px',
          lineHeight: dragEl.clientHeight + 'px'
        }
      }
    },
    _initNode(node) {
      this.rjsp.draggable(node, {
        constrain: true
      })
      // DynamicAnchors.map(anchor => this.rjsp.addEndpoint(node, anEndpoint, {
      //   anchor
      // }))
      // console.log(node.id)
      for (var i = 0; i < sourceAnchors.length; i++) {
        var sourceUUID = node.id +"$"+ sourceAnchors[i]
        var el = this.rjsp.addEndpoint(node.id, sourceEndpoint, {
          anchor: sourceAnchors[i],
          uuid: sourceUUID
        })
      }
      for (var j = 0; j < targetAnchors.length; j++) {
        var targetUUID = node.id +"$"+ targetAnchors[j]
        var el = this.rjsp.addEndpoint(node.id, targetEndpoint, {
          anchor: targetAnchors[j],
          uuid: targetUUID
        })
      }
      this.rjsp.makeTarget(node, targetEndpoint)
    },
    _initNodes(nodes) {
      nodes.map(node => this._initNode(node))
    },
    _initEdges(edges) {
      edges.map(edge => {
         let c = this.rjsp.connect({
        uuids: edge.uuids,
        editable: true
      }, Common)
      console.log(c)
      c.scope = edge.action
      this.$nextTick(_ => c.getOverlay('label').setLabel(edge.labelText))
      })
    },
    _fetchData() {
      // this.$http.get('/api/data').then(res => {
      let data = this.flowdata
      if (data.edit) {
        this.flowItem = data.flow
        this.nodes = data.nodes
        this.$nextTick(_ => {
          this._initNodes(this.$refs.nodes)
          this._initEdges(data.edges)
        })
      } else {
        this.newData()
      }
    }
  },
  mounted() {
    this.getRole()
    this.getAction()
    this.getEvent()
    this.init()
  }
}
</script>

<style lang="css" scoped>
.right-area {
  position: relative;
}

.demo {
  position: fixed;
  width: 74%;
}

.node {
  /* padding: 0 10px; */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14px;
  text-align: center;
  cursor: pointer;
  background-color: #5cadff;
}

.start,
.end {
  position: absolute;
  width: 100px;
  height: 100px;
  border: 1px solid #333;
  border-radius: 50%;
  box-sizing: border-box;
}

.task,
.auto,
.fork,
.join,
.subflow {
  position: absolute;
  width: 100px;
  height: 100px;
  border: 1px solid #333;
  border-radius: 5px;
  box-sizing: border-box;
}

.start:before {
  content: '\f29f';
  font-family: ionicons;
  font-size: 2.5em
}

.end:before {
  content: '\f29e';
  font-family: ionicons;
  font-size: 2.5em
}

.task:before {
  content: '\f213';
  font-family: ionicons;
  font-size: 2.5em
}

.auto:before {
  content: '\f13e';
  font-family: ionicons;
  font-size: 2.5em
}

.fork:before {
  content: '\f25e';
  font-family: ionicons;
  font-size: 2.5em
}

.join:before {
  content: '\f267';
  font-family: ionicons;
  font-size: 2.5em
}

.subflow:before {
  content: '\f40a';
  font-family: ionicons;
  font-size: 2.5em
}
</style>
